#include<threadpool.h>

static trd_node * trdpool_head;
static trd_node * trdpool_tail;
static pthread_t *workthreads;
//工作线程的pthread_t

void workfunc_udf(void* a){
    cout << "Undefined work func" << endl;
}

/**
 * trdpool_worktrd
 * 线程池中运行的线程
 * 通过pthread_cond来唤醒执行
 * 线程有一块inode指向的空间：包含了锁，函数指针，函数参数
 * 函数执行完毕后，自动加回单链表
 * 
 */
void* trdpool_worktrd(void *inode){
    auto tnode=(trd_node *)inode;
    while (1)
    {
        pthread_mutex_lock(tnode->trd_lock);
        pthread_cond_wait(tnode->trd_flg, tnode->trd_lock);
        
        cout << "THIS is " << pthread_self()%100 << endl;
        tnode->workfunc(tnode->arg);

        //执行完成，返回线程池
        tnode->nxt = nullptr;
        while (_CAS(&trdpool_tail->nxt, nullptr, tnode));
        trdpool_tail = tnode;
        pthread_mutex_unlock(tnode->trd_lock);
    }
    return nullptr;
}

/*
* trdpool_addwork
* 添加一个任务 从单链表中拿出节点
* 如果没有多余线程返回1 否则注册任务后，返回0（异步：返回时任务还没有完成）
*
*/
int trdpool_addwork(void (*workfunc)(void *), void *arg){
    while(1){
        auto head = trdpool_head;
        auto hnxt = head->nxt;
        //这里保证head不为空：线程池中总会剩下一个线程
        if(hnxt==nullptr)
            return 1;
        //线程池还剩一个线程，不分配，返回错误
        if(_CAS(&trdpool_head,head,hnxt)){
            //把head拿出来了
            pthread_mutex_lock(head->trd_lock);
            head->workfunc = workfunc;
            head->arg = arg;
            pthread_cond_signal(head->trd_flg);
            pthread_mutex_unlock(head->trd_lock);
            break;
        }
    }
    return 0;
}

/*
* trdpool_init
*  初始化，建立链表并分配内存空间
*  线程池不考虑回收问题：程序结束，操作系统回收
*/
void trdpool_init(int trd_num){
    assert(trd_num > 0);
    workthreads = (pthread_t*)malloc(trd_num * sizeof(pthread_t));
    trd_node *pre = nullptr;
    auto nodeptr = (trd_node *)malloc(trd_num*sizeof(trd_node));
    auto mutexptr = (pthread_mutex_t *)malloc(trd_num*sizeof(pthread_mutex_t));
    auto condptr = (pthread_cond_t *)malloc(trd_num*sizeof(pthread_cond_t));
    trdpool_tail = nodeptr;
    for (int i = 0; i < trd_num; i++){
        nodeptr->nxt = pre;
        nodeptr->trd_flg = condptr;
        nodeptr->trd_lock = mutexptr;
        pre = nodeptr++;
        pthread_cond_init(condptr++, NULL);
        pthread_mutex_init(mutexptr++, NULL);
        assert(pthread_create(workthreads + i, NULL, trdpool_worktrd, pre)==0);
    }
    trdpool_head = --nodeptr;
    LOG_MSG("trdpool_init");
}